
/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 *版权所有2002-2018原创作者。
 *
 *根据Apache许可证2.0版许可（“许可证”）；
 *除非符合许可证的规定，否则您不得使用此文件。
 *您可以在以下网址获取许可证副本：
 *
 *https://www.apache.org/licenses/LICENSE-2.0
 *
 *除非适用法律要求或书面同意，软件
 *根据许可证进行的分发是在“按原样”的基础上进行的，
 *无任何明示或暗示的保证或条件。
 *有关管理权限的特定语言，请参阅许可证和
 *许可证下的限制。
 */

package org.springframework.jmx.support;

import java.util.LinkedHashSet;
import java.util.Set;

import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.ObjectInstance;
import javax.management.ObjectName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

/**
 * Provides supporting infrastructure for registering MBeans with an
 * {@link javax.management.MBeanServer}. The behavior when encountering
 * an existing MBean at a given {@link ObjectName} is fully configurable
 * allowing for flexible registration settings.
 *
 * <p>All registered MBeans are tracked and can be unregistered by calling
 * the #{@link #unregisterBeans()} method.
 *
 * <p>Sub-classes can receive notifications when an MBean is registered or
 * unregistered by overriding the {@link #onRegister(ObjectName)} and
 * {@link #onUnregister(ObjectName)} methods respectively.
 *
 * <p>By default, the registration process will fail if attempting to
 * register an MBean using a {@link javax.management.ObjectName} that is
 * already used.
 *
 * <p>By setting the {@link #setRegistrationPolicy(RegistrationPolicy) registrationPolicy}
 * property to {@link RegistrationPolicy#IGNORE_EXISTING} the registration process
 * will simply ignore existing MBeans leaving them registered. This is useful in settings
 * where multiple applications want to share a common MBean in a shared {@link MBeanServer}.
 *
 * <p>Setting {@link #setRegistrationPolicy(RegistrationPolicy) registrationPolicy} property
 * to {@link RegistrationPolicy#REPLACE_EXISTING} will cause existing MBeans to be replaced
 * during registration if necessary. This is useful in situations where you can't guarantee
 * the state of your {@link MBeanServer}.
 *
 * @author Rob Harrop
 * @author Juergen Hoeller
 * @author Phillip Webb
 * @since 2.0
 * @see #setServer
 * @see #setRegistrationPolicy
 * @see org.springframework.jmx.export.MBeanExporter
 */
/**
 *为向
 *｛@link javax.management.MBeanServer｝。遇到时的行为
 *给定｛@link ObjectName｝处的现有MBean是完全可配置的
 *从而允许灵活的注册设置。
 *
 *<p>所有注册的MBean都会被跟踪，并且可以通过调用
 *#{@link#unregisterBeans（）}方法。
 *
 *<p>子类可以在注册MBean或
 *通过重写{@link#onRegister（ObjectName）}和
 *｛@link#onUnregister（ObjectName）｝方法。
 *
 *<p>默认情况下，如果尝试
 *使用｛@link javax.management.ObjectName｝注册MBean
 *已使用。
 *
 *<p>通过设置｛@link#setRegistrationPolicy（RegistrationPolicy）RegistrationPolicy｝
 *属性设置为｛@link RegistrationPolicy#IGNORE_EXISTING｝注册过程
 *将简单地忽略现有的MBean并将其注册。这在设置中很有用
 *其中多个应用程序希望在共享的{@link MBeanServer}中共享一个公共MBean。
 *
 *<p>设置｛@link#setRegistrationPolicy（RegistrationPolicy）RegistrationPolicy｝属性
 *到｛@link RegistrationPolicy#REPLACE_EXISTING｝将导致替换现有的MBean
 *如有必要，在注册期间。这在你不能保证的情况下很有用
 *｛@link MBeanServer｝的状态。
 *
 *@作者Rob Harrop
 *@作者于尔根·霍勒
 *@作者Phillip Webb
 *@自2.0起
 *@参见#setServer
 *@参见#setRegistrationPolicy
 *@参见org.springframework.jmx.export.MBeanExport
 */
public class MBeanRegistrationSupport {

	/**
	 * {@code Log} instance for this class.
	 */
	/**
	 *｛@code Log｝实例。
	 */
	protected final Log logger = LogFactory.getLog(getClass());

	/**
	 * The {@code MBeanServer} instance being used to register beans.
	 */
	/**
	 *用于注册bean的｛@code MBeanServer｝实例。
	 */
	@Nullable
	protected MBeanServer server;

	/**
	 * The beans that have been registered by this exporter.
	 */
	/**
	 *这个出口商已经注册的豆子。
	 */
	private final Set<ObjectName> registeredBeans = new LinkedHashSet<>();

	/**
	 * The policy used when registering an MBean and finding that it already exists.
	 * By default an exception is raised.
	 */
	/**
	 *注册MBean并发现其已存在时使用的策略。
	 *默认情况下会引发异常。
	 */
	private RegistrationPolicy registrationPolicy = RegistrationPolicy.FAIL_ON_EXISTING;


	/**
	 * Specify the {@code MBeanServer} instance with which all beans should
	 * be registered. The {@code MBeanExporter} will attempt to locate an
	 * existing {@code MBeanServer} if none is supplied.
	 */
	/**
	 *指定所有bean都应该使用的{@code MBeanServer}实例
	 *注册。｛@code MBeanExporter｝将尝试查找
	 *现有的｛@code MBeanServer｝（如果未提供）。
	 */
	public void setServer(@Nullable MBeanServer server) {
		this.server = server;
	}

	/**
	 * Return the {@code MBeanServer} that the beans will be registered with.
	 */
	/**
	 *返回将向其注册bean的{@code MBeanServer}。
	 */
	@Nullable
	public final MBeanServer getServer() {
		return this.server;
	}

	/**
	 * The policy to use when attempting to register an MBean
	 * under an {@link javax.management.ObjectName} that already exists.
	 * @param registrationPolicy the policy to use
	 * @since 3.2
	 */
	/**
	 *尝试注册MBean时要使用的策略
	 *在已经存在的｛@link javax.management.ObjectName｝下。
	 *@param registrationPolicy要使用的策略
	 *@自3.2起
	 */
	public void setRegistrationPolicy(RegistrationPolicy registrationPolicy) {
		Assert.notNull(registrationPolicy, "RegistrationPolicy must not be null");
		this.registrationPolicy = registrationPolicy;
	}


	/**
	 * Actually register the MBean with the server. The behavior when encountering
	 * an existing MBean can be configured using {@link #setRegistrationPolicy}.
	 * @param mbean the MBean instance
	 * @param objectName the suggested ObjectName for the MBean
	 * @throws JMException if the registration failed
	 */
	/**
	 *实际向服务器注册MBean。遇到时的行为
	 *可以使用{@link#setRegistrationPolicy}配置现有MBean。
	 *@param mbean mbean实例
	 *@param objectName建议的MBean的objectName
	 *如果注册失败，@throws JMException
	 */
	protected void doRegister(Object mbean, ObjectName objectName) throws JMException {
		Assert.state(this.server != null, "No MBeanServer set");
		ObjectName actualObjectName;

		synchronized (this.registeredBeans) {
			ObjectInstance registeredBean = null;
			try {
				registeredBean = this.server.registerMBean(mbean, objectName);
			}
			catch (InstanceAlreadyExistsException ex) {
				if (this.registrationPolicy == RegistrationPolicy.IGNORE_EXISTING) {
					if (logger.isDebugEnabled()) {
						logger.debug("Ignoring existing MBean at [" + objectName + "]");
					}
				}
				else if (this.registrationPolicy == RegistrationPolicy.REPLACE_EXISTING) {
					try {
						if (logger.isDebugEnabled()) {
							logger.debug("Replacing existing MBean at [" + objectName + "]");
						}
						this.server.unregisterMBean(objectName);
						registeredBean = this.server.registerMBean(mbean, objectName);
					}
					catch (InstanceNotFoundException ex2) {
						if (logger.isInfoEnabled()) {
							logger.info("Unable to replace existing MBean at [" + objectName + "]", ex2);
						}
						throw ex;
					}
				}
				else {
					throw ex;
				}
			}

			// Track registration and notify listeners.
			// 跟踪注册并通知听众。
			actualObjectName = (registeredBean != null ? registeredBean.getObjectName() : null);
			if (actualObjectName == null) {
				actualObjectName = objectName;
			}
			this.registeredBeans.add(actualObjectName);
		}

		onRegister(actualObjectName, mbean);
	}

	/**
	 * Unregisters all beans that have been registered by an instance of this class.
	 */
	/**
	 *注销已由此类的实例注册的所有bean。
	 */
	protected void unregisterBeans() {
		Set<ObjectName> snapshot;
		synchronized (this.registeredBeans) {
			snapshot = new LinkedHashSet<>(this.registeredBeans);
		}
		if (!snapshot.isEmpty()) {
			logger.debug("Unregistering JMX-exposed beans");
			for (ObjectName objectName : snapshot) {
				doUnregister(objectName);
			}
		}
	}

	/**
	 * Actually unregister the specified MBean from the server.
	 * @param objectName the suggested ObjectName for the MBean
	 */
	/**
	 *实际上是从服务器上注销指定的MBean。
	 *@param objectName建议的MBean的objectName
	 */
	protected void doUnregister(ObjectName objectName) {
		Assert.state(this.server != null, "No MBeanServer set");
		boolean actuallyUnregistered = false;

		synchronized (this.registeredBeans) {
			if (this.registeredBeans.remove(objectName)) {
				try {
					// MBean might already have been unregistered by an external process
					// MBean可能已被外部进程注销
					if (this.server.isRegistered(objectName)) {
						this.server.unregisterMBean(objectName);
						actuallyUnregistered = true;
					}
					else {
						if (logger.isInfoEnabled()) {
							logger.info("Could not unregister MBean [" + objectName + "] as said MBean " +
									"is not registered (perhaps already unregistered by an external process)");
						}
					}
				}
				catch (JMException ex) {
					if (logger.isInfoEnabled()) {
						logger.info("Could not unregister MBean [" + objectName + "]", ex);
					}
				}
			}
		}

		if (actuallyUnregistered) {
			onUnregister(objectName);
		}
	}

	/**
	 * Return the {@link ObjectName ObjectNames} of all registered beans.
	 */
	/**
	 *返回所有已注册bean的｛@link ObjectName ObjectNames｝。
	 */
	protected final ObjectName[] getRegisteredObjectNames() {
		synchronized (this.registeredBeans) {
			return this.registeredBeans.toArray(new ObjectName[0]);
		}
	}


	/**
	 * Called when an MBean is registered under the given {@link ObjectName}. Allows
	 * subclasses to perform additional processing when an MBean is registered.
	 * <p>The default implementation delegates to {@link #onRegister(ObjectName)}.
	 * @param objectName the actual {@link ObjectName} that the MBean was registered with
	 * @param mbean the registered MBean instance
	 */
	/**
	 *当MBean在给定的｛@link ObjectName｝下注册时调用。允许
	 *子类，以便在注册MBean时执行附加处理。
	 *<p>默认实现委托给{@link#onRegister（ObjectName）}。
	 *@param objectName注册MBean的实际｛@link objectName｝
	 *@param mbean已注册的mbean实例
	 */
	protected void onRegister(ObjectName objectName, Object mbean) {
		onRegister(objectName);
	}

	/**
	 * Called when an MBean is registered under the given {@link ObjectName}. Allows
	 * subclasses to perform additional processing when an MBean is registered.
	 * <p>The default implementation is empty. Can be overridden in subclasses.
	 * @param objectName the actual {@link ObjectName} that the MBean was registered with
	 */
	/**
	 *当MBean在给定的｛@link ObjectName｝下注册时调用。允许
	 *子类，以便在注册MBean时执行附加处理。
	 *<p>默认实现为空。可以在子类中重写。
	 *@param objectName注册MBean的实际｛@link objectName｝
	 */
	protected void onRegister(ObjectName objectName) {
	}

	/**
	 * Called when an MBean is unregistered under the given {@link ObjectName}. Allows
	 * subclasses to perform additional processing when an MBean is unregistered.
	 * <p>The default implementation is empty. Can be overridden in subclasses.
	 * @param objectName the {@link ObjectName} that the MBean was registered with
	 */
	/**
	 *当MBean在给定的｛@link ObjectName｝下未注册时调用。允许
	 *在MBean未注册时执行附加处理的子类。
	 *<p>默认实现为空。可以在子类中重写。
	 *@param objectName注册MBean的｛@link objectName｝
	 */
	protected void onUnregister(ObjectName objectName) {
	}

}
